#include "xsdl.h"
#include <SDL2/SDL.h>
#include <iostream>
#include <QDebug>
using namespace std;
#pragma comment(lib, "SDL2.lib")
static bool InitVideo()
{
    static bool is_first = true;
    static mutex mux;
    unique_lock<mutex>sdl_lock(mux);
    if(!is_first)return true;
    is_first = false;
    if(SDL_Init(SDL_INIT_VIDEO))
    {
        cout << SDL_GetError() << endl;
        return false;
    }
    SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1");
    return true;

}

XSDL::XSDL()
{

}

bool XSDL::InIt(int w, int h,
                  Format FMT)
{
    if(w < 0 || h < 0)
    {
        cout << "args erro" << endl;
        return false;
    }
    InitVideo(); //初始化sdl
    unique_lock<mutex>sdl_lock(mtx_);//智能锁出栈自动解锁
    width_ = w;
    height_ = h;
    fmt_ = FMT;

    if(!win_)
    {
        if(!wind_id_)
        {
            win_ = SDL_CreateWindow("", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, w, h, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
        }
        else
        {
            win_ = SDL_CreateWindowFrom(wind_id_);
            SDL_ShowWindow(win_);
//            SDL_SetWindowResizable(win_, SDL_TRUE);
        }
    }
    if(!win_)
    {
        cout << SDL_GetError() << endl;
    }

    //创建渲染器
    if(Texture){
        SDL_DestroyTexture(Texture);
        Texture = NULL;
    }
    if(Renderer) {
        SDL_DestroyRenderer(Renderer);
        Renderer = NULL;
    }

    Renderer = SDL_CreateRenderer(win_, -1, SDL_RENDERER_ACCELERATED);
    if(!Renderer)
    {
        cerr << SDL_GetError() << endl;
        return false;
    }

    //创建材质
    unsigned int sdl_fmt = SDL_PIXELFORMAT_ABGR8888;
    switch(FMT)
    {
        case XVideoView::RGBA:
            sdl_fmt = SDL_PIXELFORMAT_RGBA8888;
            break;
        case  XVideoView::ARGB:
            sdl_fmt = SDL_PIXELFORMAT_ABGR8888;
            break;
        case  XVideoView::YUV420P:
            sdl_fmt = SDL_PIXELFORMAT_IYUV;
            break;
       case  XVideoView::BGRA:
            sdl_fmt = SDL_PIXELFORMAT_BGRA8888;
            break;
       default:
            break;

    }
    std::cout << "create texture format:" << sdl_fmt << "------ "<< SDL_PIXELFORMAT_IYUV<< std::endl;
    Texture = SDL_CreateTexture(Renderer, sdl_fmt, SDL_TEXTUREACCESS_STREAMING, w, h);
    if(!Texture)
    {
        cerr << SDL_GetError() << endl;
        return false;
    }
    cout << "init accomplish" << endl;

    return true;
}

 bool XSDL::Draw(const unsigned char * data, int linesize)
 {
     if(!data)return false;
     unique_lock<mutex>sdl_lock(mtx_);//智能锁出栈自动解锁
     if(!Texture || !Renderer || !win_ || width_ < 0 || height_ < 0)
     {
         return false;
     }
     if(linesize <= 0)
     {
         switch(fmt_)
         {
             case XVideoView::RGBA:
                 linesize = width_ * 4;
                 break;
             case XVideoView::ARGB:
                 linesize = width_ * 4;
                 break;
             case XVideoView::YUV420P:
                 linesize = width_;
                 break;
             default:
                break;
         }
     }
     if(linesize <= 0)
         return false;
    auto ret = SDL_UpdateTexture(Texture, NULL, data, linesize);
    if(ret != 0)
    {
        cout << SDL_GetError() << endl;
        return false;
    }

    SDL_RenderClear(Renderer);//清空屏幕

    //材质复制到渲染器
    SDL_Rect rect;
    SDL_Rect* prect = nullptr;
    if(scale_w_ > 0){
        rect.x = 0;
        rect.y = 0;
        rect.w = scale_w_;
        rect.h = scale_h_;
        prect = &rect;

    }

    ret = SDL_RenderCopy(Renderer, Texture, NULL, prect);
    if(ret != 0)
    {
        cout << SDL_GetError() << endl;
        return false;
    }
    SDL_RenderPresent(Renderer);
     return true;
 }

void save_yuv_frame(const unsigned char* y, int y_pitch,
                    const unsigned char* u, int u_pitch,
                    const unsigned char* v, int v_pitch)
{
    std::ofstream out_file("save_yuv_frame.yuv", std::ios::binary);
    if(!out_file)
    {
        std::cout << "create file fail" << std::endl;
    }
    int w = 400, h = 300;

    for(int i = 0; i < h; i++)
    {
        out_file.write(reinterpret_cast<const char*>(y + i * y_pitch), w);
    }

    for(int i = 0; i < h / 2; i++)
    {
        out_file.write(reinterpret_cast<const char*>(u + i * u_pitch), w / 2);
    }

    for(int i = 0; i < h / 2; i++)
    {
        out_file.write(reinterpret_cast<const char*>(v + i * v_pitch), w / 2);
    }

    out_file.close();
    std::cout << "YUV帧已保存: " << "save_yuv_frame.yuv" << std::endl;
}

bool XSDL::Draw(const unsigned char* y, int y_pitch,
                const unsigned char* u, int u_pitch,
                const unsigned char* v, int v_pitch)
{
    if(!y || !u || ! v)return false;
    unique_lock<mutex> sdl_lock(mtx_);
    static int flag = 0;
    if(!flag)
    {
        save_yuv_frame(y, y_pitch,
                       u, u_pitch,
                       v, v_pitch);
        flag = 1;

    }
    if(!Texture || !Renderer || !win_ || width_ <= 0 || height_  <= 0)return false;
    auto re = SDL_UpdateYUVTexture(Texture, NULL, y, y_pitch,
                                   u, u_pitch,
                                   v, v_pitch);
    if(re != 0)
    {
        cout << SDL_GetError() << endl;
        return false;
    }

    SDL_RenderClear(Renderer);

    SDL_Rect rect;
    SDL_Rect* prect = nullptr;
    if(scale_w_ > 0)
    {
        rect.x = 0;
        rect.y = 0;
        rect.w = scale_w_;
        rect.h = scale_h_;
        prect = &rect;
    }
    re = SDL_RenderCopy(Renderer, Texture, NULL, prect);
    if(re != 0)
    {
        std::cout << SDL_GetError()<< endl;
        return false;
    }

    SDL_RenderPresent(Renderer);
//    std::cout << "SDL_RenderPresent succes" << std::endl;
    return true;
}


bool XSDL::IsExit()
{
 SDL_Event ev;
 SDL_WaitEventTimeout(&ev, 1);
 if(ev.type == SDL_QUIT)
    return true;

 return false;
}

void XSDL::Close()
{
   unique_lock<mutex>sdl_lock(mtx_);//智能锁出栈自动解锁
   if(Texture){
       SDL_DestroyTexture(Texture);
       Texture = NULL;
   }

   if(Renderer) {
       SDL_DestroyRenderer(Renderer);
       Renderer = NULL;
   }

   if(win_) {
       SDL_DestroyWindow(win_);
       win_ = NULL;
   }
}
